package ar.edu.itba.it.paw.web;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import ar.edu.itba.it.paw.domain.Category;
import ar.edu.itba.it.paw.domain.OrderProducts;
import ar.edu.itba.it.paw.domain.Product;
import ar.edu.itba.it.paw.domain.Transaction;
import ar.edu.itba.it.paw.domain.User;
import ar.edu.itba.it.paw.domain.exceptions.InsufficientProductsException;
import ar.edu.itba.it.paw.domain.exceptions.InvalidOperationException;
import ar.edu.itba.it.paw.services.ProductServices;
import ar.edu.itba.it.paw.web.command.AddProductForm;
import ar.edu.itba.it.paw.web.command.BuyProductForm;
import ar.edu.itba.it.paw.web.command.EditProductForm;
import ar.edu.itba.it.paw.web.command.TransactionCategoryForm;
import ar.edu.itba.it.paw.web.validator.AddProductFormValidator;
import ar.edu.itba.it.paw.web.validator.BuyProductFormValidator;
import ar.edu.itba.it.paw.web.validator.EditProductFormValidator;

@Controller
public class ProductController {

	private ProductServices product_services;
	private AddProductFormValidator addProduct_validator;
	private EditProductFormValidator editProduct_validator;
	private BuyProductFormValidator buyProduct_validator;

	@Autowired
	public ProductController(ProductServices product_services,AddProductFormValidator addProduct_validator,EditProductFormValidator editProduct_validator, BuyProductFormValidator buyProduct_validator){
		this.product_services = product_services;
		this.addProduct_validator = addProduct_validator;
		this.editProduct_validator = editProduct_validator;
		this.buyProduct_validator = buyProduct_validator;
	}

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView addProduct(){
		ModelAndView mav = new ModelAndView();
		mav.addObject("addProductForm", new AddProductForm());
		mav.addObject("categoryList",product_services.getCategories());
		return mav;
	}

	@RequestMapping(method = RequestMethod.POST)
	public ModelAndView addProduct( HttpSession session, AddProductForm form, Errors errors){
		addProduct_validator.validate(form, errors);
		if(errors.hasErrors()){
			ModelAndView errorMav = new ModelAndView();
			errorMav.addObject("categoryList", product_services.getCategories());
			return errorMav;
		}
		User user = (User) session.getAttribute("usuario");
		if(user == null){
			return new ModelAndView("redirect:../user/index");
		}

		product_services.addProduct(new Product(form.getProduct_name(),form.getDescription(), new Date() ,form.getCategory(),form.getPrice(),form.getQuantity(),form.isState(),user));
		return new ModelAndView("product/addedProduct");
	}

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView editProduct(HttpSession session){

		User user = (User) session.getAttribute("usuario");
		if(user == null){
			return null;
		}
		ModelAndView mav = new ModelAndView();
		mav.addObject("productList",product_services.getUserProducts(user));

		return mav;
	}

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView editForm(@RequestParam("id") Product product){
		ModelAndView mav = new ModelAndView();
		mav.addObject("editProductForm",new EditProductForm(product.getName(),product.getDescription(),product.getCategory(),product.getState(),product.getId()));
		mav.addObject("categoryList",product_services.getCategories());
		//cargar en el form los datos del producto. Debe llegarme un producto segun el prod que seleccione
		return mav;
	}

	@RequestMapping(method = RequestMethod.POST)
	public ModelAndView editForm(HttpSession session, EditProductForm form, Errors errors){
		editProduct_validator.validate(form, errors);
		if(errors.hasErrors()){
			ModelAndView errorMav = new ModelAndView();
			errorMav.addObject("categoryList", product_services.getCategories());
			return errorMav;
		}
		User user = (User) session.getAttribute("usuario");
		if(user == null){
			return new ModelAndView("redirect:../user/index");
		}
		product_services.editProduct(new Product(form.getProduct_id(),form.getProduct_name(),form.getDescription(),new Date(),form.getCategory(),1,1,form.isState(),1,user));
		return new ModelAndView("product/modifiedProduct");
	}

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView viewProduct(@RequestParam("id") Product product) {
		ModelAndView mav = new ModelAndView();
		product_services.visitProduct(product);
		mav.addObject("product",product);
		List<Product> list =  product_services.getUserProducts(product.getOwner());
		list.remove(product);
		mav.addObject("productList",list);
		mav.addObject("buyProductForm",new BuyProductForm());
		return mav;
	}

	@RequestMapping(method = RequestMethod.POST)
	public ModelAndView viewProduct(HttpSession session, BuyProductForm form, Errors errors){
		User user = (User) session.getAttribute("usuario");
		if(user == null){
			ModelAndView mav = new ModelAndView("redirect:../user/index");
			mav.addObject("red",1);
			return mav;
		}
		
		buyProduct_validator.validate(form, errors);
		Product product = null;
		
		product = product_services.getProduct(form.getProduct().getId());
		
		if(errors.hasErrors()){
			ModelAndView mav = new ModelAndView();
			mav.addObject("product",product);
			List<Product> list =  product_services.getUserProducts(product.getOwner());
			list.remove(product);
			mav.addObject("productList",list);
			return mav;
		}
		
		try{
			product_services.buy(new Transaction(user, product.getOwner(), form.getQuantity(), new Date() , product));
		}catch(InsufficientProductsException e){
			errors.rejectValue("quantity", "too_many");
			ModelAndView mav = new ModelAndView();
			mav.addObject("product",product);
			List<Product> list =  product_services.getUserProducts(product.getOwner());
			list.remove(product);
			mav.addObject("productList",list);
			return mav;
		}catch(InvalidOperationException e){
			errors.rejectValue("quantity", "invalid_operation");
			ModelAndView mav = new ModelAndView();
			mav.addObject("product",product);
			List<Product> list =  product_services.getUserProducts(product.getOwner());
			list.remove(product);
			mav.addObject("productList",list);
			return mav;
		}
		
		ModelAndView mav = new ModelAndView("product/boughtProduct");
		mav.addObject("owner",product.getOwner());
		//	System.out.println(product.getOwner());
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView listProducts(){
		ModelAndView mav = new ModelAndView();
		ArrayList<Category> category_list = new ArrayList<Category>();
		category_list.add(new Category(0,"Todos"));
		category_list.addAll(product_services.getCategories());
		
		mav.addObject("productList", product_services.getAllProducts());
		mav.addObject("categoryList", category_list);
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public ModelAndView listProducts(@RequestParam("category") Category category) {
		ModelAndView mav = new ModelAndView();
		ArrayList<Category> category_list = new ArrayList<Category>();
		category_list.add(new Category(0,"Todos"));
		category_list.addAll(product_services.getCategories());
		
		if(category == null){
			mav.addObject("productList",product_services.getAllProducts());
		}else if(!category.getName().equals("Todos")){
			mav.addObject("productList", product_services.getProductsByCategory(category));
		}
		mav.addObject("categoryList", category_list);
		mav.addObject("category", category);
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView orderProducts(@RequestParam("option") String option, @RequestParam("order") String sequence){	
		ModelAndView mav = new ModelAndView();
		OrderProducts order = null;
		boolean ascending;
		mav.addObject("option",option);
		if(sequence.equals("asc")){
			mav.addObject("order","desc");
			ascending = true;
		}else if(sequence.equals("desc")){
			mav.addObject("order","asc");
			ascending = false;
		}else{
			return null;
		}
		if(option.equals("nombre")){
			order = new OrderProducts("nombre",ascending,0);
		}else if(option.equals("precio")){
			order = new OrderProducts("precioUnitario",ascending,0);
		}else if(option.equals("fecha")){
			order = new OrderProducts("fechaPublicacion",ascending,0);
		}else{
			return null;
		}
		mav.addObject("productList",product_services.getAllProducts(order));
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView categoryTransaction(){
		ModelAndView mav = new ModelAndView();
		mav.addObject("categoryList",product_services.getCategories());
		mav.addObject("transactionCategoryForm", new TransactionCategoryForm());
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public ModelAndView categoryTransaction(TransactionCategoryForm form) {
		ModelAndView mav = new ModelAndView();
		mav.addObject("categoryList", product_services.getCategories());
		mav.addObject("transactionCategoryForm", form);
		mav.addObject("transactionList",
		product_services.getTransactionByCategory(form.getCategory()));
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView countTransactionCategory(){
		ModelAndView mav = new ModelAndView();
		mav.addObject("transMap",product_services.countTransactionsByCategory());
		return mav;
	}

}
